package com.cg.leetcode;

import org.junit.Test;

import java.util.*;

/**
 * 332.重新安排行程
 *
 * @author cg
 * @program LeetCode->LeetCode_332
 * @create 2022-08-30 15:18
 **/
public class LeetCode_332 {

    @Test
    public void test332() {
        ArrayList<List<String>> tickets = new ArrayList<>();
        tickets.add(Arrays.asList("MUC", "LHR"));
        tickets.add(Arrays.asList("JFK", "MUC"));
        tickets.add(Arrays.asList("SFO", "SJC"));
        tickets.add(Arrays.asList("LHR", "SFO"));
        System.out.println(findItinerary(tickets));
        tickets.clear();
        tickets.add(Arrays.asList("JFK", "SFO"));
        tickets.add(Arrays.asList("JFK", "ATL"));
        tickets.add(Arrays.asList("SFO", "ATL"));
        tickets.add(Arrays.asList("ATL", "JFK"));
        tickets.add(Arrays.asList("ATL", "SFO"));
        System.out.println(findItinerary(tickets));
        tickets.clear();
        tickets.add(Arrays.asList("JFK", "KUL"));
        tickets.add(Arrays.asList("JFK", "NRT"));
        tickets.add(Arrays.asList("NRT", "JFK"));
        System.out.println(findItinerary(tickets));
    }

    /**
     * 给你一份航线列表 tickets ，其中 tickets[i] = [from_i, to_i] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。
     * 所有这些机票都属于一个从 JFK（肯尼迪国际机场）出发的先生，所以该行程必须从 JFK 开始。如果存在多种有效的行程，请你按字典排序返回最小的行程组合。
     * 例如，行程 ["JFK", "LGA"] 与 ["JFK", "LGB"] 相比就更小，排序更靠前。
     * 假定所有机票至少存在一种合理的行程。且所有的机票 必须都用一次 且 只能用一次。
     * <p>
     * 示例 1：
     * 输入：tickets = [["MUC","LHR"],["JFK","MUC"],["SFO","SJC"],["LHR","SFO"]]
     * 输出：["JFK","MUC","LHR","SFO","SJC"]
     * <p>
     * 示例 2：
     * 输入：tickets = [["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]]
     * 输出：["JFK","ATL","JFK","SFO","ATL","SFO"]
     * 解释：另一种有效的行程是 ["JFK","SFO","ATL","JFK","ATL","SFO"] ，但是它字典排序更大更靠后。
     * <p>
     * 提示：
     * 1 <= tickets.length <= 300
     * tickets[i].length == 2
     * from_i.length == 3
     * to_i.length == 3
     * from_i 和 to_i 由大写英文字母组成
     * from_i != to_i
     *
     * @param tickets
     * @return
     */
    public List<String> findItinerary(List<List<String>> tickets) {
        result = new LinkedList<>();
        map = new HashMap<>();
        for (List<String> ticket : tickets) {
            Map<String, Integer> temp;
            String start = ticket.get(0);
            String end = ticket.get(1);
            if (map.containsKey(start)) {
                temp = map.get(start);
                temp.put(end, temp.getOrDefault(end, 0) + 1);
            } else {
                temp = new TreeMap<>();
                temp.put(end, 1);
            }
            map.put(start, temp);
        }
        result.add("JFK");
        helper(tickets.size());
        return result;
    }

    List<String> result;
    Map<String, Map<String, Integer>> map;

    private boolean helper(int ticketNum) {
        if (result.size() == ticketNum + 1) {
            return true;
        }
        String last = result.get(result.size() - 1);
        if (map.containsKey(last)) {
            for (Map.Entry<String, Integer> entry : map.get(last).entrySet()) {
                int count = entry.getValue();
                if (count > 0) {
                    result.add(entry.getKey());
                    entry.setValue(count - 1);
                    if (helper(ticketNum)) {
                        return true;
                    }
                    result.remove(result.size() - 1);
                    entry.setValue(count);
                }
            }
        }
        return false;
    }
}
